SuperStrict

Rem
bbdoc: Simple Sequencing Engine
about: This module provides a simple sequencing engine implementation. Each sequence is 
built by any number of "steps" which can be handled in the order they were created.
Each step has convenience methods to assign/track integer step identifiers, store and retrieve a data object,
expire steps as well as track/set initialization of each sequence step. Steps operate on a simple
FIFO stack, and the functions and methods provided primarily work on the currently active step
(which is on top of the stack).
End Rem
Module jmd.Sequence
Import brl.linkedlist

ModuleInfo "Version: 1.2"
ModuleInfo "Author: Jonathan Decker"
ModuleInfo "License: GNU GPL v3"
ModuleInfo "SVN: http://jmd-blitzmax-modules.googlecode.com/svn/trunk/jmd.mod/sequence.mod"

ModuleInfo "History: 1.2"
ModuleInfo "History: 	Changed how history is annotated"
ModuleInfo "History:	Changed SVN information"
ModuleInfo "History: 1.1"
ModuleInfo "History:	Fixed typo"
ModuleInfo "History: 1.0"
ModuleInfo "History:	Initial release."

Rem
bbdoc: TSequence Type
about: This is the main type you will be dealing with
End Rem
Type TSequence
	'List of sequence steps
	Field list:TList
	
	Rem
	bbdoc: alternative for #CreateSequence()
	End Rem
	Function Create:TSequence()
		Local a:TSequence
		a = New TSequence
		a.list=CreateList()
		Return a
	End Function
	
	Rem
	bbdoc: alternative for #SequenceAdd()
	End Rem
	Method Add(stepNum:Int,thisDuration:Int=0,data:Object=Null)
		Local a:TSequenceStep
		
		If Not list Then list=CreateList()
		a = New TSequenceStep
		a.info=stepNum
		a.init=False
		a.data=data
		a.timeStamp=MilliSecs()
		a.duration=thisDuration
		list.addlast(a)
	End Method

	Rem
	bbdoc: alternative for #SequenceClear()
	End Rem
	Method Clear()
		If Not list=Null Then list.clear()
	End Method
	
	Rem
	bbdoc: alternative for #SequenceGet()
	End Rem
	Method Get:Int()
		Local a:TSequenceStep
		If Not list Return 0
		a=TSequenceStep(list.first())
		Return a.info
	End Method
	
	Rem
	bbdoc: alternative for #SequenceData()
	End Rem
	Method Data:Object()
		If Not list Return Null
		Return TSequenceStep(list.first()).data
	End Method
	Method DoNext() 
		list.removefirst()
	End Method
	
	Rem
	bbdoc: alternative for #SequenceInit()
	End Rem
	Method Init:Int()
		Local a:TSequenceStep
		If Not list Return 0
		a=TSequenceStep(list.first())
		Local b:Int = a.init
		a.init=True
		Return b
	End Method

	Rem
	bbdoc: alternative for #SequenceReInit()
	End Rem
	Method ReInit()
		TSequenceStep(list.first()).init=False
	End Method

	Rem
	bbdoc: alternative for #SequenceCount()
	End Rem
	Method Count:Int()
		Return list.Count()
	End Method
	
	Rem
	bbdoc: alternative for #SequenceAutoExpire()
	End Rem
	Method AutoExpire()
		If Self.Expire() Then Self.DoNext()
	End Method
	
	Rem
	bbdoc: alternative for #SequenceExpire()
	End Rem
	Method Expire:Int()
		Local a:TSequenceStep
		Local deltaT:Int=MilliSecs()-TSequenceStep(list.first()).timestamp
		Local dur:Int = TSequenceStep(list.first()).duration
		
		If deltaT > dur And dur>0
			Return True
		Else
			Return False
		EndIf
	End Method
End Type


Rem
bbdoc: TSequenceStep Type
about: This type is used behind the scenes by the #TSequence type to store information about
each step in the sequence.  You should never have to deal with this type directly.
End Rem
Type TSequenceStep
	'Initialization tracking
	Field init:Int
	'Step info (normally step number)
	Field info:Int
	'Additional data to store with step
	Field data:Object
	'Autotimeout, True/False
	Field autotimeout:Int
	'Millisecs timestamp at creation of step
	Field timestamp:Int
	'Duration of this step, in Millisecs.
	'<1 is infinite duration
	Field duration:Int
End Type

Rem
bbdoc: Create a new sequence
returns: A #TSequence object
about: Creates a new #TSequence object. 
Alternatively you can use the @TSequence.Create() method
End Rem
Function CreateSequence:TSequence()
	Local a:TSequence=TSequence.Create()
	Return a
End Function

Rem
bbdoc: Add a new step to a sequence
returns: nothing
about: Adds a new step to a sequence. It is usually advantageous to create constants for the
@stepNum parameter to make code easier to read.
#SequenceExpire() and #SequenceAutoExpire() can be used to see if this step is expired.
#SequenceDoNext() can be used to advance to the next step in the sequence.
@stepData parameter is used to associate any data you wish with this step of the sequence.
It can be retrieved later with #SequenceData(). Defaults to #Null.
Alternatively you can use the @TSequence.Add() method
End Rem
Function SequenceAdd(seq:TSequence,stepNum:Int,stepDur:Int,stepData:Object=Null)
	seq.Add(stepNum,stepDur,stepData)
End Function

Rem
bbdoc: Clear all steps from the current sequence
returns: nothing
about: Use to clear all steps from a sequence so you can start fresh.
Alternatively you can use the @TSequence.Clear() method
End Rem
Function SequenceClear(seq:TSequence)
	seq.Clear()
End Function

Rem
bbdoc: Get the current sequence step
returns: A @stepNum identifier originally set with #SequenceAdd()
about: Use this in a Select statement or If statment to see what step the sequence is currently on.
Alternatively you can use the @TSequence.Get() method
End Rem
Function SequenceGet:Int(seq:TSequence)
	Return seq.Get()
End Function

Rem
bbdoc: Get the data object associated with the current sequence step
returns: any object originally passed to @stepData with #SequenceAdd()
about: There are often times where you will need to associate some data with each sequence step.
For example, you may want to store a message to display with each sequence step:
&{
SEQ.Add(STEP_INTRO,0,"We are in the intro screen!")
}

which could later be retrieved like:

&{
print String(SEQ.Data())
}

Alternatively you can use the @TSequence.Data() method

note: Also note that more complex data objects can be stored/retrieved such as #TList and #TMap objects,
allowing you to associate a virtually unlimited amount of data with each step of the sequence.
End Rem
Function SequenceData:Object(seq:TSequence)
	Return seq.Data()
End Function

Rem
bbdoc: Advance to the next step of the sequence
returns: nothing
about: Effectively pops the current step off of the stack so that the next sequence in line
will be at the top of the stack. This is the command to use to move from one step of a sequence
to the next.
Alternatively you can use the @TSequence.DoNext() method
End Rem
Function SequenceDoNext(seq:TSequence)
	seq.DoNext()
End Function

Rem
bbdoc: Sequence step initialization
returns: @True or @False
about: When a sequence step is first created (using #SequenceAdd()), its initialization state
is set to false.  When this function is called for the first time, it sets its internal initialization
state to true, and returns false. This allows the code wrapped in a conditional expression to be
executed the first time it is run only. This lets you cleanly initialize anything you need to
when a sequence step first starts.
note: See #SequenceReInit() if you would like to reset the internal initialization state back to false.
This allows #SequenceInit() to return false once again so that your initialization code can be
re-run.
Alternatively you can use the @TSequence.Init() method
End Rem
Function SequenceInit:Int(seq:TSequence)
	Return seq.Init()
End Function

Rem
bbdoc: Reinitialize a sequence step
returns: nothing
about: When a sequence step is first created (using #SequenceAdd()), its initialization state
is set to false.  When this #SequenceInit() is called for the first time, it sets its internal initialization
state to true, and returns false. This allows the code wrapped in a conditional expression to be
executed the first time it is run only. This lets you cleanly initialize anything you need to
when a sequence step first starts.
Alternatively you can use the @TSequence.ReInit() method
End Rem
Function SequenceReInit(seq:TSequence)
	seq.ReInit()
End Function

Rem
bbdoc: Auto-expire a sequence step
returns: nothing
about: This is a convience function which does nothing more than call #SequenceExpire(), and then
call #SequenceDoNext() if #SequenceExpire() returns true.
Alternatively you can use the @TSequence.AutoExpire() method

note: Sequence steps created with 0 @stepDur with #SequenceAdd() are considered infinite, and will
not expire!
End Rem
Function SequenceAutoExpire(seq:TSequence)
	seq.AutoExpire()
End Function

Rem
bbdoc: Check if a sequence step has expired
returns: @True or @False
about: Use this to check if a sequence is expired. Use in combination with #SequenceDoNext() to
move from step to step in the sequence.
Alternatively you can use the @TSequence.Expire() method

note: Sequence steps created with 0 @stepDur with #SequenceAdd() are considered infinite, and will
not expire!
End Rem
Function SequenceExpire:Int(seq:TSequence)
	Return seq.Expire()
End Function



